package mn.idax.exchange.otc.service.impl;

import mn.idax.exchange.auth.bean.AuthInfo;
import mn.idax.exchange.common.UTCTimeUtil;
import mn.idax.exchange.common.bean.ResponseData;
import mn.idax.exchange.otc.domain.capital.ChangeListData;
import mn.idax.exchange.otc.domain.openapi.*;
import mn.idax.exchange.otc.entity.Account;
import mn.idax.exchange.otc.entity.OTCBusinessApply;
import mn.idax.exchange.otc.entity.OTCSysDictionaryItem;
import mn.idax.exchange.otc.entity.User;
import mn.idax.exchange.otc.enums.AccountTransactionEnum;
import mn.idax.exchange.otc.enums.DictEnum;
import mn.idax.exchange.otc.enums.response.OTCAdResponseEnum;
import mn.idax.exchange.otc.enums.response.UserResponseEnum;
import mn.idax.exchange.otc.mapper.*;
import mn.idax.exchange.otc.service.AccountCapitalService;
import mn.idax.exchange.otc.service.OTCSysDictionaryItemService;
import mn.idax.exchange.otc.service.OpenApiService;
import mn.idax.exchange.otc.util.Base64;
import mn.idax.exchange.otc.util.CryptoUtils;
import mn.idax.exchange.otc.util.Encrypt;
import mn.idax.exchange.otc.util.LogUtils;
import mn.idax.exchange.otc.vo.PageVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Author jension
 * @Date Created in 14:48 2021/3/12
 */
@Service
public class OpenApiServiceImpl implements OpenApiService {

    @Autowired
    OpenApiMapper openApiMapper;
    @Autowired
    AccountCapitalService accountCapitalService;
    @Autowired
    UserMapper userMapper;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    AccountTransactionMapper accountTransactionMapper;
    @Autowired
    AccountMapper accountMapper;
    @Autowired
    OTCSysDictionaryItemService otcSysDictionaryItemService;
    @Autowired
    OTCBusinessApplyMapper otcBusinessApplyMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = {RuntimeException.class, Exception.class})
    public ResponseData userSync(UserSyncRequest userSyncRequest) {
        LogUtils.info(this.getClass(), "OpenApiServiceImpl_userSync .{}", userSyncRequest.toString());
        User user = userMapper.selectByPrimaryKey(userSyncRequest.getUserId());
        if (!Objects.isNull(user)) {
            return ResponseData.error(UserResponseEnum.USER_ALREADY_EXISTS.getRespCode(), UserResponseEnum.USER_ALREADY_EXISTS.getRespMsg());

        }
        User userMobile = userMapper.selectByAccount(userSyncRequest.getMobile());
        if (!Objects.isNull(userMobile)) {
            return ResponseData.error(UserResponseEnum.MOBILE_ALREADY_EXISTS.getRespCode(), UserResponseEnum.MOBILE_ALREADY_EXISTS.getRespMsg());
        }

        String passwordSalt = CryptoUtils.createRandomSalt();
        String passwordHash = CryptoUtils.hashPassword(userSyncRequest.getPassword(), passwordSalt);
        String passwordNew = CryptoUtils.hashPassword_bak(userSyncRequest.getPassword(), passwordSalt);
        user = new User(userSyncRequest.getUserId(), userSyncRequest.getMobile(), userSyncRequest.getCertificateNo(), passwordHash, passwordNew, passwordSalt, userSyncRequest.getNickName());
        // 增加user记录
        openApiMapper.userInsert(user);

        // 增加Certificate记录
        openApiMapper.certificateInsert(userSyncRequest);

        // 增加userindex记录
        openApiMapper.userIndexInsert(user);

        // 增加商家
        otcBusinessApplyMapper.insertSelective(new OTCBusinessApply(null, user.getId(), new Date(), 1, "", new Date(), user.getId()));

        // 初始化account
        // 查询支持币种
        List<OTCSysDictionaryItem> otcSysDictionaryItem = otcSysDictionaryItemService.listItem(DictEnum.COIN_CODE.getCode(), null);
        openApiMapper.accountInsert(userSyncRequest, otcSysDictionaryItem);
        return ResponseData.success();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = {RuntimeException.class, Exception.class})
    public ResponseData changeAccount(ChangeAccountRequest changeAccountRequest) {
        LogUtils.info(this.getClass(), "OpenApiServiceImpl_changeAccount .{}", changeAccountRequest.toString());
        /** 补充参数 **/
        // 查询accountId
        Account account = accountCapitalService.getBalances(changeAccountRequest.getUserId(), changeAccountRequest.getCoinId());
        if (Objects.isNull(account)) {
            return ResponseData.error(OTCAdResponseEnum.TRANSACTION_CURRENT_NOT_EXIST.getCode(), "");
        }

        ChangeListData changeListData = new ChangeListData();
        BeanUtils.copyProperties(changeAccountRequest, changeListData);

        changeListData.setFrozenChange(BigDecimal.ZERO);
        changeListData.setAccountId(account.getId());
        changeListData.setTransactionType(AccountTransactionEnum.TRANSACTIONTYPE_TRANSFER.getCode());
        changeListData.setSourceId(0);
        accountCapitalService.changeAccount(changeListData, null);
        return ResponseData.success();
    }

    @Override
    public List<GetBalanceDTO> getBalance(GetBalanceRequest getBalanceRequest) {
        return accountMapper.openApiGetBalance(getBalanceRequest);
    }

    @Override
    public ResponseData loginSync(LoginSyncRequest loginSyncRequest) {
        LogUtils.info(this.getClass(), "OpenApiServiceImpl_loginSync ", loginSyncRequest.toString());
        // 查询用户
        User user = userMapper.selectByPrimaryKey(loginSyncRequest.getUserId());
        if (Objects.isNull(user)) {
            return ResponseData.error(UserResponseEnum.USER_ISNOTEXIST.getRespCode(), UserResponseEnum.USER_ISNOTEXIST.getRespMsg());
        }
        long nowDate = UTCTimeUtil.getUTCTimeLong();
        AuthInfo authInfo = new AuthInfo(loginSyncRequest.getUserId(), 1, user.getEmail(), "--", true,
                new Date(nowDate), 1, loginSyncRequest.getExpireHour(), 1);
        //生成token
        String token = Encrypt.getToken(authInfo);
        String key = mn.idax.exchange.auth.constant.Constant.USERTOKEN + ":" + loginSyncRequest.getUserSourceCode() + "_" + authInfo.getId();
        addOrUpdateToken(key, token, loginSyncRequest.getExpireHour());
        return ResponseData.success(new LoginSyncDTO(token, loginSyncRequest.getExpireHour()));
    }

    @Override
    public ResponseData logoutSync(LoginSyncRequest loginSyncRequest) {
        String key = mn.idax.exchange.auth.constant.Constant.USERTOKEN + ":" + loginSyncRequest.getUserSourceCode() + "_" + loginSyncRequest.getUserId();
        stringRedisTemplate.delete(key);
        return ResponseData.success();
    }

    @Override
    public PageVo<ChangeAccountLogDTO> queryChangeAccountLog(ChangeAccountLogRequest changeAccountLogRequest) {
        PageVo<ChangeAccountLogDTO> pageVo = new PageVo<>();
        List<ChangeAccountLogDTO> changeAccountLogDTOS = accountTransactionMapper.queryUserIdAndTypePage(changeAccountLogRequest);
        pageVo.setData(changeAccountLogDTOS);
        pageVo.setPageIndex(changeAccountLogRequest.getPageIndex());
        changeAccountLogRequest.setPageIndex(null);
        List<ChangeAccountLogDTO> totalRecord = accountTransactionMapper.queryUserIdAndTypePage(changeAccountLogRequest);
        pageVo.setTotalRecord(totalRecord.size());

        return pageVo;
    }


    public void addOrUpdateToken(String key, String token, int expire) {

        AuthInfo authInfo = Base64.decodeToken(token);
        int expireHour = authInfo.getExpireHour();
        if (authInfo != null && expireHour == 0) {
            stringRedisTemplate.opsForValue().set(key, token);
        }
        if (authInfo != null && expireHour > 0) {
            stringRedisTemplate.opsForValue().set(key, token, expire, TimeUnit.HOURS);
        }
//        LogUtils.info(this.getClass(),"====addOrUpdateToken====key"+key+"token="+token+"expireHour="+expireHour);
    }
}
